package com.kun.repeatSubmit.interceptor;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kun.repeatSubmit.annotation.RepeatSubmit;
import com.kun.repeatSubmit.redis.RedisCache;
import com.kun.repeatSubmit.request.RepeatableReadRequestWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author fangkun
 * @create 2023-05-10-11:12
 */
@Component
public class RepeatSubmitInterceptor implements HandlerInterceptor {

    public static final String REPEAT_PARAMS = "repeat_params";
    public static final String REPEAT_TIME = "repeat_time";
    public static final String REPEAT_SUBMIT_KEY = "repeat_submit_key";
    public static final String HEADER = "Authorization";

    @Autowired
    RedisCache redisCache;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //所以的controller方法都会被封装成HandlerMethod
        if (handler instanceof HandlerMethod){
            //分析注解
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            RepeatSubmit repeatSubmit = method.getAnnotation(RepeatSubmit.class);
            //如果注解存在&&请求重复
            if (repeatSubmit != null){
                if (isRepeatSubmit(request,repeatSubmit)){
                    //拦截返回错误信息
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("status",500);
                    map.put("message",repeatSubmit.message());
                    response.setContentType("application/json;charset=utf-8");
                    response.getWriter().write(new ObjectMapper().writeValueAsString(map));
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit repeatSubmit) {
        //获取请求参数字符串
        String nowParams = "";
        //RepeatableReadRequestWrapper 说明是JSON格式
        if (request instanceof RepeatableReadRequestWrapper){
            try {
                nowParams = ((RepeatableReadRequestWrapper) request).getReader().readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //否则说明参数是key-value格式
        if (StringUtils.isEmpty(nowParams)){
            try {
                nowParams = new ObjectMapper().writeValueAsString(request.getParameterMap());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }

        //包装参数和当前时间
        HashMap<String, Object> nowDataMap = new HashMap<>();
        nowDataMap.put(REPEAT_PARAMS,nowParams);
        nowDataMap.put(REPEAT_TIME,System.currentTimeMillis());

        //获取请求信息，组装key
        String requestURI = request.getRequestURI();
        String header = request.getHeader(HEADER);
        String cacheKey = REPEAT_SUBMIT_KEY + requestURI + header.replace("Bearer ","");

        //根据key查找redis
        Object cacheObject = redisCache.getCacheObject(cacheKey);

        if (cacheObject != null){
            //这里说明不是第一次，判断是否为重复请求（参数、时间）
            Map<String, Object> cacheMap = (Map<String, Object>) cacheObject;
            if (compareParams(cacheMap, nowDataMap) && compareTime(cacheMap, nowDataMap, repeatSubmit.interval())){
                return true;
            }
        }

        //到这里说明是第一次访问
        redisCache.setCacheObject(cacheKey,nowDataMap,repeatSubmit.interval(), TimeUnit.MILLISECONDS);
        return false;
    }

    private boolean compareTime(Map<String, Object> cacheMap, HashMap<String, Object> nowDataMap, int interval) {
        Long nowTime = (Long) nowDataMap.get(REPEAT_TIME);
        Long cacheTime = (Long) cacheMap.get(REPEAT_TIME);
        if (nowTime - cacheTime < interval) {
            return true;
        }
        return false;
    }

    private boolean compareParams(Map<String, Object> cacheMap, HashMap<String, Object> nowDataMap) {
        String cacheParams = (String) cacheMap.get(REPEAT_PARAMS);
        String nowParams = (String) nowDataMap.get(REPEAT_PARAMS);
        return nowParams.equals(cacheParams);
    }

}
